/** 
Copyright (c) 2010, Sheikh Abdul Wahid Ahmed
Details @ http://extremecodeworld.codeplex.com/license
**/

using System;
using EXtremecode.Utils;
using System.Collections;
using System.Data;
using System.Data.OleDb;
using EXtremecode.DataAccessLayer;
using EXtremecode.DataAccessLayer.Configurations;
using System.Text;
using EXtremecode;
using System.Web;
using EXtremecode.Common;
using System.Data.Common;
using System.Collections.Generic;

namespace EXtremecode.DataAccessLayer
{
	public class DataAccessorCollection:Hashtable
	{
		static DataAccessorCollection s_daCollection;
		static Hashtable s_htTransactions=new Hashtable();
		static string s_defaultConnectionName=null;
		private DataAccessorCollection()
		{
			try
			{
				string strPath=System.AppDomain.CurrentDomain.BaseDirectory + Provider.ConnectionsPath;
				DataTable dtConnections=null;
				DataAccessorCollection daCol=this;
				try
				{
					dtConnections=GetDataTableForXmlFile(strPath);
				}
				catch{}
				//If no connection defined ,create connection with empty implementation.
				if(dtConnections == null) 
					daCol.AddAccessor("Empty","","Empty",true);
				else
				{
					foreach(DataRow dr in dtConnections.Rows)
					{
						bool isDefault=false;
						string connectionName="";
						string connectionString="";
						string connectionType="";
						bool encrypted = false;

						try{isDefault=Convert.ToBoolean(dr[Constants.ColumnNames_Connections.IS_DEFAULT]);}
						catch{}
						try{connectionName=Convert.ToString(dr[Constants.ColumnNames_Connections.NAME]);}
						catch{}
						try{connectionString=Convert.ToString(dr[Constants.ColumnNames_Connections.CONNECTION_STRING]);}
						catch{}
						try{connectionType=Convert.ToString(dr[Constants.ColumnNames_Connections.TYPE]);}
						catch{}
						try{encrypted=Convert.ToBoolean(dr[Constants.ColumnNames_Connections.ENCRYPTED]);}
						catch{}

						if(encrypted)
						{
							connectionString = Utils.DataEncryptor.Instance.GetDecryptedString(connectionString);
						}

						daCol.AddAccessor(connectionName,connectionString,connectionType,isDefault);
					}
				}
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				Logging.Logger.Write();
			}
			
		}
		private static DataTable GetDataTableForXmlFile(string filePath)
		{
			try
			{
				DataSet ds=new DataSet();
				ds.ReadXml(filePath);
				if(ds.Tables.Count==0 || ds.Tables[0].Rows.Count==0)
					throw new Exception("[UE] No connection found"); 
				return ds.Tables[0];
				
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}
		}
		
		public DataAccessor AddAccessor(string sAccessorName,string sConnectionURL,string accessorType)
		{
			return AddAccessor(sAccessorName,sConnectionURL,accessorType,false); 
		}
		public DataAccessor AddAccessor(string sAccessorName,string sConnectionURL,string accessorType,bool isDefault)
		{
			try
			{
				DataAccessor dataAcr=null;
				if(ValidateInputForAccessorCreation(sAccessorName,sConnectionURL))
				{
				
					try
					{
				
						Type typeDataAccessor=Type.GetType(string.Format("EXtremecode.DataAccessLayer.{0}DataAccessor",accessorType));
						if(typeDataAccessor != null)dataAcr=Activator.CreateInstance(typeDataAccessor,new object[2]{sAccessorName,sConnectionURL}) as DataAccessor;
						
						//if no connection is already declared as default, Make this connection to default.
						if(s_defaultConnectionName==null || isDefault)
							s_defaultConnectionName=sAccessorName;
				
					}
					catch(Exception ex)
					{
						throw new Exception(string.Format("[UE] Accessor of name [{0}], cant be created",sAccessorName),ex);
					}
				}
				if(dataAcr!=null)base.Add(sAccessorName,dataAcr);
				return dataAcr;
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}
		}
		public bool Commit()
		{
			try
			{
				bool bSucceeded=true;
				foreach(object key in this.Keys)
				{
					bSucceeded &= this[key.ToString()].Commit();
				}
				return bSucceeded;
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				Logging.Logger.Write();
			}
		}
		public void SetTransactionType(IsolationLevel isolationLevel)
		{
			try
			{
				foreach(object key in this.Keys)
				{
					this[key.ToString()].TransactionType=isolationLevel;
				}
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				Logging.Logger.Write();
			}
		}
		public bool Rollback()
		{
			try
			{
				bool bSucceeded=true;
				foreach(object key in this.Keys)
				{
					bSucceeded &= this[key.ToString()].Rollback();
				}
				return bSucceeded;	
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				Logging.Logger.Write();
			}
		}
		public DataAccessor this[string key]
		{
			get
			{
				if(!base.ContainsKey(key))
				{
					throw Logging.Logger.Write(
						new Exception(
							string.Format("Connection with the key '{0}' has not been defined",key)));
				}
				return (base[key] as DataAccessor);
			}
			
		}
		public static DataAccessorCollection  Instance
		{
			get
			{
				
				return CreateInstance();
			}
		}
		public static DataAccessor DefaultAccessor
		{
			get
			{
				return Instance[s_defaultConnectionName]; 
			}
		}

		public static Hashtable Transactions
		{
			get
			{
				return s_htTransactions; 
			}
		}
		private static DataAccessorCollection CreateInstance()
		{
			if(s_daCollection == null)
				s_daCollection=new DataAccessorCollection();
			return s_daCollection;
		}
		public static string DefaultAccessorName
		{
			get
			{
				if(s_defaultConnectionName==null)// means object is not initialized at yet
				{
					CreateInstance();
				}
				return s_defaultConnectionName; 
			}
		}
		private  bool ValidateInputForAccessorCreation(string sAccessorName,string sConnectionURL)
		{
			try
			{
				if(sAccessorName==null || sAccessorName.Trim().Length==0)
					throw new Exception("[UE] Invalid Accessor Name");
				if(base.ContainsKey(sAccessorName))
					throw new Exception(string.Format("[UE] Accessor of name '{0}', already exsists",sAccessorName));
				return true;
			}
			catch(Exception ex)
			{
				throw Logging.Logger.Write(ex);
			}
			finally
			{
				//Logging.Logger.Write();
			}
				
		}
		
		
		
		
		
		
		#region Hidden Methods
		public override void Add(object key, object value)
		{
			throw new Exception("[UE] method is not allowed");
		}
		public override void CopyTo(Array array, int arrayIndex)
		{
			throw new Exception("[UE] method is not allowed");

		}
		#endregion
	 


	}
}
